package mock.bean;

import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;

//import static own.stu.jobgib.playown.stateMachine.constant.SoConstant.PARENT_ORDERCODE;

public class SoServiceImpl {

    public static final List<Integer> ORDER_PAID = Lists.newArrayList(2, 3);
    public static final Integer PAYMENT_CHANEL_WX = 30;
    public static final Integer PAYMENT_CHANEL_GIFTCARD = 90;//礼品卡支付
    public static final Integer PARENT_ORDERCODE = 0;
    public static final Integer ORDER_PAYMENT_STATUS_3 = 3;
    public static final Integer ACCOUNT_TYPE_PAY = 3;

    static int MAX_PAY_DETAIL_COUNT = 2;
    static int MAX_PAY_DETAIL_COUNT_WITH_ZERO_RETURN_AMOUNT = 1;

    @Resource
    private SoMapper mapper;

    @Resource
    private SoReturnMapper soReturnMapper;

    public BigDecimal calOrderCanReturnGiftCardAmount(SoPO soPO, List<SoOrderpayFllowPO> orderPayFlows, BigDecimal canReturnTotalAmount) {
        BigDecimal realGiftAmount = BigDecimal.ZERO;
        if (BigDecimal.ZERO.compareTo(canReturnTotalAmount) == 0) {
            return realGiftAmount;
        }

        // 无父单的订单
        if (PARENT_ORDERCODE.equals(soPO.getParentOrderCode())) {
            return soPO.getGiftCardAmount();
        }

        // 父单中的微信支付金额
        BigDecimal wxPayAmount = sumAmount(orderPayFlows, SoOrderpayFllowPO::getAmount,
                v->v.getAmount() != null,
                v -> Objects.equals(v.getPaymentChannel(), PAYMENT_CHANEL_WX));

        List<SoPO> childPOs = mapper.selectByParentOrderCode(soPO.getParentOrderCode());

        BigDecimal alreadlyRefundWxAmount = BigDecimal.ZERO; //已退的微信金额
        for (SoPO tmp : childPOs) {
            if (Objects.equals(tmp.getOrderCode(), soPO.getOrderCode())) {
                continue;
            }

            // 另外一单已经申请取消退款
            if (ORDER_PAID.contains(tmp.getOrderPaymentStatus()) && Objects.equals(tmp.getOrderStatus(), OrderStatus.CLOSED.getCode())) {
                if(tmp.getUserFee() != null){
                    alreadlyRefundWxAmount = wxPayAmount.min(tmp.getUserFee()).abs(); // 优先扣除微信金额，所以这里计算最小的金额，就是微信已退金额
                }
            }

            // 另外一单申请了售后退款
            if (BigDecimal.ZERO.compareTo(alreadlyRefundWxAmount) == 0){
                List<SoReturnPO> soReturnList = soReturnMapper.findByOrderCode(tmp.getOrderCode(), tmp.getCompanyId());
                if(CollectionUtils.isEmpty(soReturnList)){
                    continue; // 没有申请售后
                }
                BigDecimal returnTotalAmount = sumAmount(soReturnList, SoReturnPO::getActualReturnAmount, v -> v.getActualReturnAmount() != null);
                BigDecimal returnGiftCardAmount = sumAmount(soReturnList, SoReturnPO::getGiftCardAmount, v -> v.getGiftCardAmount() != null);
                alreadlyRefundWxAmount = returnTotalAmount.subtract(returnGiftCardAmount);
            }
        }

        if (BigDecimal.ZERO.compareTo(alreadlyRefundWxAmount) == 0){
            return canReturnTotalAmount.subtract(canReturnTotalAmount.min(wxPayAmount));
        }
        // 当前订单可退金额 - (父单中的微信支付金额 - 已退的订单 微信支付金额） = 礼品卡支付金额
        return canReturnTotalAmount.subtract(wxPayAmount.subtract(alreadlyRefundWxAmount));
    }

    /**
     * 组装混合支付退款明细
     *
     * @param canReturnTotalAmount 退款总金额
     * @param giftCardAmount       礼品卡退款金额
     * @param userId               用户id
     * @param soOrderPayFlowPOList 支付流水
     * @return
     */
    public static List<RefundManageDetailInDTO> builtRefundDetail(BigDecimal canReturnTotalAmount,
                                                                  BigDecimal giftCardAmount,
                                                                  Long userId,
                                                                  List<OrderPaySimpleData> soOrderPayFlowPOList) {

        List<RefundManageDetailInDTO> refundDetailList = new ArrayList<>();

        if (canReturnTotalAmount == null || canReturnTotalAmount.compareTo(BigDecimal.ZERO) < 0) {
            return refundDetailList;
        }

        BigDecimal gitCardPayAmount = BigDecimal.ZERO;
        if (giftCardAmount != null && giftCardAmount.compareTo(BigDecimal.ZERO) > 0) {
            gitCardPayAmount = giftCardAmount;
        }

        if(canReturnTotalAmount.compareTo(giftCardAmount) < 0){
            giftCardAmount = BigDecimal.ZERO;
        }

        int count = 0;
        boolean zeroAmountFlag = BigDecimal.ZERO.compareTo(canReturnTotalAmount) == 0;
        int maxCount = zeroAmountFlag ? MAX_PAY_DETAIL_COUNT_WITH_ZERO_RETURN_AMOUNT : MAX_PAY_DETAIL_COUNT;
        for (OrderPaySimpleData orderPayFlow : soOrderPayFlowPOList) {

            if (count++ >= maxCount) {
                break;
            }

            RefundManageDetailInDTO creaditDetailInDTO = new RefundManageDetailInDTO();
            creaditDetailInDTO.setRefundAccountId(userId);//用户ID

            if (Objects.equals(orderPayFlow.getPaymentChannel(), PAYMENT_CHANEL_GIFTCARD)) {

                if (gitCardPayAmount.compareTo(BigDecimal.ZERO) <= 0) {
                    if(!zeroAmountFlag) {
                        continue;
                    }
                }

                creaditDetailInDTO.setRefundPayNo(orderPayFlow.getPaymentNo());
                creaditDetailInDTO.setRefundSubAmount(gitCardPayAmount);
            } else {

                if (canReturnTotalAmount.subtract(gitCardPayAmount).compareTo(BigDecimal.ZERO) <= 0) {
                    if(!zeroAmountFlag) {
                        continue;
                    }
                }
                creaditDetailInDTO.setRefundPayNo(orderPayFlow.getPaymentNo());
                creaditDetailInDTO.setRefundSubAmount(canReturnTotalAmount.subtract(gitCardPayAmount));
            }

            creaditDetailInDTO.setRefundAccountType(ACCOUNT_TYPE_PAY);
            refundDetailList.add(creaditDetailInDTO);
        }

        return refundDetailList;
    }


    private <T> BigDecimal sumAmount(List<T> list, Function<T, BigDecimal> map, Predicate<T>... filter){
        Stream<T> stream = list.stream();
        for (Predicate p : filter) {
            stream = stream.filter(p);
        }

        return stream
                .map(map)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }
}
